/**
 * Copyright (c) [2025] [AGIROS] 
 * [travoddsgen] is licensed under Mulan PSL v2. 
 * You can use this software according to the terms and conditions of the Mulan PSL v2. 
 * You may obtain a copy of Mulan PSL v2 at: 
 *          http://license.coscl.org.cn/MulanPSL2 
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 
 * See the Mulan PSL v2 for more details.
 */ 

#ifndef ast_h__
#define ast_h__

#include <string>
#include <vector>
#include <stdint.h>
#include "AstVisitor.h"

// Base class for all AST nodes
class ASTNode {
public:
    virtual ~ASTNode() = default;
    virtual void accept(AstVisitor& visitor) = 0;
};

// List node template
template <typename T>
class ListNode : virtual public ASTNode {
public:
    void add(T node) { nodes_.push_back(node); } 
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::vector<T> nodes_;
};

// Definition node
class DefinitionNode : virtual public ASTNode {
public:
    virtual ~DefinitionNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

// Specification node
class SpecificationNode : virtual public ASTNode {
public:
    SpecificationNode() : definitions_(nullptr) { s_instance = this; }
     static SpecificationNode* get_instance() { 
         return s_instance; 
     }
    void set_definitions(ListNode<DefinitionNode*>* definitions) { definitions_ = definitions; }
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    static SpecificationNode* s_instance;
    ListNode<DefinitionNode*>* definitions_;
};

class ModuleDclNode : virtual public DefinitionNode {
public:
    ModuleDclNode(std::string* identifier, ListNode<DefinitionNode*>* definitions)
        : identifier_(identifier), definitions_(definitions) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    ListNode<DefinitionNode*>* definitions_;
};

class IncludeDclNode : virtual public DefinitionNode {
public:
    IncludeDclNode(std::string* file) : file_(file) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); } 
public:
    std::string* file_;
};

// Constant declaration node
class ConstDclNode : virtual public DefinitionNode {
public:
    ConstDclNode(ConstTypeNode* type, std::string* identifier, ConstExprNode* expression)
        : type_(type), identifier_(identifier), expression_(expression) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    ConstTypeNode* type_;
    ConstExprNode* expression_;
};

// ConstType node
class ConstTypeNode : virtual public ASTNode {
public:
    virtual ~ConstTypeNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

class PositiveIntConstNode : virtual public ASTNode {
public:
    PositiveIntConstNode() {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

class ConstExprNode : virtual public PositiveIntConstNode {
public:
    virtual ~ConstExprNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

// Expression nodes
class OrExprNode : virtual public ConstExprNode {
public:
    OrExprNode(OrExprNode* left, XorExprNode* right) : left_(left), right_(right) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    OrExprNode* left_;
    XorExprNode* right_;
};

class XorExprNode : virtual public ConstExprNode{
public:
    XorExprNode(XorExprNode* left, AndExprNode* right) :left_(left), right_(right) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    XorExprNode* left_;
    AndExprNode* right_;
};

class AndExprNode : virtual public ConstExprNode {
public:
    AndExprNode(AndExprNode* left, ShiftExprNode* right) : left_(left), right_(right) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    AndExprNode* left_;
    ShiftExprNode* right_;
};

class ShiftExprNode : virtual public ConstExprNode{
public:
    enum class ShiftOp {
        LEFT, 
        RIGHT, 
        NONE
    };
    ShiftExprNode(ShiftExprNode* left, AddExprNode* right, ShiftOp op) : left_(left), right_(right), op_(op) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    ShiftExprNode* left_;
    AddExprNode* right_;
    ShiftOp op_;
};

class AddExprNode : virtual public ConstExprNode {
public:
    enum class AddOp {
        PLUS, 
        MINUS, 
        NONE
    };
    AddExprNode(AddExprNode* left, MultExprNode* right, AddOp op) : left_(left), right_(right), op_(op) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    AddExprNode* left_;
    MultExprNode* right_;
    AddOp op_;
};

class MultExprNode : virtual public ConstExprNode{
public:
    enum class MultOp {
        MULT, 
        DIV, 
        MOD, 
        NONE
    };
    MultExprNode(MultExprNode* left, UnaryExprNode* right, MultOp op) : left_(left), right_(right), op_(op) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    MultExprNode* left_;
    UnaryExprNode* right_;
    MultOp op_;
};

class UnaryExprNode : virtual public ConstExprNode{
public:
    enum class UnaryOp {
        PLUS, 
        MINUS, 
        NOT, 
        NONE
    };
    UnaryExprNode(UnaryOp op, PrimaryExprNode* expr) : op_(op), expr_(expr) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    UnaryOp op_;
    PrimaryExprNode* expr_;
};

class PrimaryExprNode : virtual public ASTNode {
public:
    PrimaryExprNode(ScopedNameNode* scopedName, LiteralNode* literal, ConstExprNode* expr) : scopedName_(scopedName), literal_(literal), constExpr_(expr) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    ScopedNameNode* scopedName_;
    LiteralNode* literal_;
    ConstExprNode* constExpr_;
};

class LiteralNode : virtual public ASTNode {
public:
    enum class LiteralType {
        INTEGER, 
        FLOAT,
        STRING, 
        BOOLEAN
    };
    LiteralNode(std::string* value) : type_(LiteralType::STRING), bvalue_(false), ivalue_(0), svalue_(*value) {} 
    LiteralNode(int value) : type_(LiteralType::INTEGER), bvalue_(false), ivalue_(value) {}
    LiteralNode(double value) : type_(LiteralType::FLOAT), bvalue_(false), fvalue_(value) {}
    LiteralNode(bool value) : type_(LiteralType::BOOLEAN), bvalue_(value), ivalue_(0) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    LiteralType type_;
    bool bvalue_;
    int ivalue_;
    double fvalue_;
    std::string svalue_;
};

class TypeDclNode : virtual public DefinitionNode {
public:
    virtual ~TypeDclNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

class ConstrTypeDclNode : virtual public TypeDclNode {
public:
    ConstrTypeDclNode() {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
};

class TypeDefDclNode : virtual public TypeDclNode {
public:
    TypeDefDclNode(std::string* identifier, TypeSpecNode* refType, ListNode<FixedArraySizeNode*>* dims) 
    : identifier_(identifier), refType_(refType), dims_(dims) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    TypeSpecNode* refType_;
    ListNode<FixedArraySizeNode*>* dims_;
};

class TypeSpecNode : virtual public ASTNode {
public:
    virtual ~TypeSpecNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

class SimpleTypeSpecNode : virtual public TypeSpecNode, virtual public ConstTypeNode {
public:
    virtual ~SimpleTypeSpecNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

class ScopedNameNode : virtual public SimpleTypeSpecNode {
public:
    ScopedNameNode(std::string* identifier) { components_.push_back(identifier); }    
    void add(std::string* component) { components_.push_back(component); }
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::vector<std::string*> components_;
};

class TemplateTypeSpecNode : virtual public TypeSpecNode {
public:
    virtual ~TemplateTypeSpecNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

// Base type node
class BaseTypeNode : virtual public SimpleTypeSpecNode {
public:
    enum class Type {
        SHORT, 
        LONG, 
        LONGLONG, 
        USHORT, 
        ULONG, 
        ULONGLONG, 
        CHAR, 
        WCHAR, 
        BOOLEAN, 
        UCHAR, 
        FLOAT, 
        DOUBLE, 
        LONG_DOUBLE
    };
    BaseTypeNode(Type type) : type_(type) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
    uint32_t getTypeSize() const {
        switch (type_) {
            case Type::SHORT:
                return 2;
            case Type::LONG:
                return 4;
            case Type::LONGLONG:
                return 8;
            case Type::USHORT:
                return 2;
            case Type::ULONG:
                return 4;
            case Type::ULONGLONG:
                return 8;
            case Type::CHAR:
                return 1;
            case Type::WCHAR:
                return 2;
            case Type::BOOLEAN:
                return 1;
            case Type::UCHAR:
                return 1;
            case Type::FLOAT:
                return 4;
            case Type::DOUBLE:
                return 8;
            case Type::LONG_DOUBLE:
                return 16;
            default:
                return 0; // Unknown type
        }
    }
public:
    Type type_;
};

// Sequence type node
class SequenceTypeNode : virtual public TemplateTypeSpecNode {
public:
    SequenceTypeNode(TypeSpecNode* type, PositiveIntConstNode* size = nullptr) : type_(type), size_(size) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    TypeSpecNode* type_;
    PositiveIntConstNode* size_;
};

// String type node
class StringTypeNode : virtual public TemplateTypeSpecNode, virtual public ConstTypeNode {
public:
    StringTypeNode(PositiveIntConstNode* size = nullptr) : size_(size) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    PositiveIntConstNode* size_;
};

// Wide string type node
class WideStringTypeNode : virtual public TemplateTypeSpecNode, public ConstTypeNode {
public:
    WideStringTypeNode(PositiveIntConstNode* size = nullptr) : size_(size) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    PositiveIntConstNode* size_;
};

// Fixed point type node
class FixedPtTypeNode : virtual public TemplateTypeSpecNode {
public:
    FixedPtTypeNode(PositiveIntConstNode* digits, PositiveIntConstNode* scale) : digits_(digits), scale_(scale) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    PositiveIntConstNode* digits_;
    PositiveIntConstNode* scale_;
};

// Map type node
class MapTypeNode : virtual public TemplateTypeSpecNode {
public:
    MapTypeNode(TypeSpecNode* keyType, TypeSpecNode* valueType, PositiveIntConstNode* size = nullptr) : keyType_(keyType), valueType_(valueType), size_(size) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    TypeSpecNode* keyType_;
    TypeSpecNode* valueType_;
    PositiveIntConstNode* size_;
};

class StructDclNode : virtual public ConstrTypeDclNode {
public:
    virtual ~StructDclNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

// Type annotation node
class TypeAnnotationNode : virtual public ASTNode {
public:
    enum class AnnotationType {
        FINAL, 
        APPENDABLE, 
        MUTABLE, 
        NESTED, 
        BIT_BOUND
    };
    TypeAnnotationNode(AnnotationType annotation) : annotation_(annotation), value_(nullptr) {}
    void setValue(PositiveIntConstNode* value) { value_ = value; }
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
    std::string toString() {
        switch (annotation_) {
            case AnnotationType::FINAL:
                return "final";
            case AnnotationType::APPENDABLE:
                return "appendable";
            case AnnotationType::MUTABLE:
                return "mutable";
            case AnnotationType::NESTED:
                return "nested";
            case AnnotationType::BIT_BOUND:
                return "bit_bound()";
            default:
                return "unknown";
        }
    }
    static TypeAnnotationNode::AnnotationType getExtensibility(ListNode<TypeAnnotationNode*>* annotations_) {
        if (!annotations_) {
            return TypeAnnotationNode::AnnotationType::FINAL;
        }
        for (auto& annotation : annotations_->nodes_) {
            if (annotation->annotation_ == TypeAnnotationNode::AnnotationType::FINAL) {
                return TypeAnnotationNode::AnnotationType::FINAL;
            }
            if (annotation->annotation_ == TypeAnnotationNode::AnnotationType::APPENDABLE) {
                return TypeAnnotationNode::AnnotationType::APPENDABLE;
            }
            if (annotation->annotation_ == TypeAnnotationNode::AnnotationType::MUTABLE) {
                return TypeAnnotationNode::AnnotationType::MUTABLE;
            }
        }
        return TypeAnnotationNode::AnnotationType::FINAL;
    }
public:
    AnnotationType annotation_;
    PositiveIntConstNode* value_;
};

// Struct definition node
class StructDefNode : virtual public StructDclNode {
public:
    StructDefNode(std::string* identifier, ListNode<MemberNode*>* members, ListNode<TypeAnnotationNode*>* annotations, ScopedNameNode* parent) : identifier_(identifier), members_(members), annotations_(annotations), parent_(parent) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    ScopedNameNode* parent_;
    ListNode<MemberNode*>* members_;
    ListNode<TypeAnnotationNode*>* annotations_;
};

// Member annotation node
class MemberAnnotationNode : virtual public ASTNode {
public:
    enum class AnnotationType {
        ID_ANNOTATION, 
        KEY_ANNOTATION, 
        MUST_UNDERSTAND_ANNOTATION, 
        OPTION_ANNOTATION, 
        SHARED_ANNOTATION, 
        VALUE_ANNOTATION
    };
    MemberAnnotationNode(AnnotationType annotation) : annotation_(annotation), value_(nullptr) {}
    void setValue(PositiveIntConstNode* value) {
        value_ = value;
    }
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
    std::string toString() {
        switch (annotation_) {
        case AnnotationType::ID_ANNOTATION:
            return "id";
        case AnnotationType::KEY_ANNOTATION:
            return "key";
        case AnnotationType::MUST_UNDERSTAND_ANNOTATION:
            return "must_understand";
        case AnnotationType::OPTION_ANNOTATION:
            return "option";
        case AnnotationType::SHARED_ANNOTATION:
            return "shared";
        case AnnotationType::VALUE_ANNOTATION:
            return "value";
        default:
            return "unknown";
        }
    }
public:
    AnnotationType annotation_;
    PositiveIntConstNode* value_;
};

// Member node
class MemberNode : virtual public ASTNode {
public:
    MemberNode(TypeSpecNode* type, std::string* identifier, ListNode<FixedArraySizeNode*>* array_dims, ListNode<MemberAnnotationNode*>* annotations) : type_(type), identifier_(identifier), arrayDims_(array_dims), annotations_(annotations) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
    bool isShared() {
        if (!annotations_) {
            return false;
        }
        for (auto& annotation : annotations_->nodes_) {
            if (annotation->annotation_ == MemberAnnotationNode::AnnotationType::SHARED_ANNOTATION) {
                return true;
            }
        }
        return false;
    }
    bool isKey() {
        if (!annotations_) {
            return false;
        }
        for (auto& annotation : annotations_->nodes_) {
            if (annotation->annotation_ == MemberAnnotationNode::AnnotationType::KEY_ANNOTATION) {
                return true;
            }
        }
        return false;
    }
    PositiveIntConstNode* getIdNode() {
        if (!annotations_) {
            return nullptr;
        }
        for (auto& annotation : annotations_->nodes_) {
            if (annotation->annotation_ == MemberAnnotationNode::AnnotationType::ID_ANNOTATION) {
                return annotation->value_;
            }
        }
        return nullptr;
    }
public:
    TypeSpecNode* type_;
    std::string* identifier_;
    ListNode<FixedArraySizeNode*>* arrayDims_;
    ListNode<MemberAnnotationNode*>* annotations_;
};

// Fixed array size node
class FixedArraySizeNode : virtual public ASTNode {
public:
    FixedArraySizeNode(PositiveIntConstNode* size) : size_(size) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    PositiveIntConstNode* size_;
};

// Struct forward declaration node
class StructForwardDclNode : virtual public StructDclNode {
public:
    StructForwardDclNode(std::string* identifier) : identifier_(identifier) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
};

class UnionDclNode : virtual public ConstrTypeDclNode {
public:
    virtual ~UnionDclNode() = default;
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
};

// Union definition node
class UnionDefNode : virtual public UnionDclNode {
public:
    UnionDefNode(std::string* identifier, SwitchTypeSpecNode* switchType, ListNode<CaseNode*>* cases, ListNode<TypeAnnotationNode*>* annotations) : identifier_(identifier), switchType_(switchType), cases_(cases), annotations_(annotations) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    SwitchTypeSpecNode* switchType_;
    ListNode<CaseNode*>* cases_;
    ListNode<TypeAnnotationNode*>* annotations_;
};

class SwitchTypeSpecNode : virtual public ASTNode {
public:
    SwitchTypeSpecNode(BaseTypeNode* node, bool isKey = false) : type_(node), scopedName_(nullptr), key_(isKey) {}
    SwitchTypeSpecNode(ScopedNameNode* node, bool isKey = false) : type_(nullptr), scopedName_(node), key_(isKey) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    bool key_;
    BaseTypeNode* type_;
    ScopedNameNode* scopedName_;
};

// Case node
class CaseNode : virtual public ASTNode {
public:
    CaseNode(ListNode<CaseLabelNode*>* labels, ListNode<MemberNode*>* members) : labels_(labels), members_(members) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    ListNode<CaseLabelNode*>* labels_;
    ListNode<MemberNode*>* members_;
};

// Case label node
class CaseLabelNode : virtual public ASTNode {
public:
    CaseLabelNode(ConstExprNode* expression) : expression_(expression) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    ConstExprNode* expression_;
};

// Union forward declaration node
class UnionForwardDclNode : virtual public UnionDclNode {
public:
    UnionForwardDclNode(std::string* identifier) : identifier_(identifier) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
};

// Enum declaration node
class EnumDclNode : virtual public ConstrTypeDclNode {
public:
    EnumDclNode(std::string* identifier, ListNode<EnumeratorNode*>* enumerators, ListNode<TypeAnnotationNode*>* annotations) : identifier_(identifier), enumerators_(enumerators), annotations_(annotations) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    ListNode<EnumeratorNode*>* enumerators_;
    ListNode<TypeAnnotationNode*>* annotations_;
};

// Enumerator node
class EnumeratorNode : virtual public ASTNode {
public:
    EnumeratorNode(std::string* identifier, PositiveIntConstNode* value) : identifier_(identifier), value_(value) {}
    void accept(AstVisitor& visitor) override { visitor.visit(*this); }
public:
    std::string* identifier_;
    PositiveIntConstNode* value_;
};

#endif // ast_h__
